﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using WMSSoft.Lib.Basic;
using WMSSoft.Lib.Const;
using WMSSoft.Lib.Enums;
using WMSSoft.Lib.Interfaces;

namespace WMSSoft.Lib.WinKStart
{
    public delegate void DataSourceUpdate_EventHandler(object sender, Model.MenuConfig.DataSource e); 

    public class cDataSourcesReader
    {
        private bool m_Autorefresh = false;
        private int m_RefreshIntervall = 600;
        private cStartmenuItem m_Data = null;
        private Dictionary<string, Model.MenuConfig.DataSource> m_Items = new Dictionary<string, Model.MenuConfig.DataSource>();        

        public event DataSourceUpdate_EventHandler UpdatedDataSource;

        public cDataSourcesReader()
        {
            //nothing todo
            m_Data = new cStartmenuItem("DATASOURCESROOT", "DataSources", eLinkExecutionTypes.Program, "", eExecutionProcedure.Unknown,
                                        eItemType.Root, "", null, null, "", "", "", "");
        }

        #region Properties
        /// <summary>
        /// If this is True the DataSources will be automatic be updated
        /// </summary>
        public bool AutoRefresh
        {
            get { return m_Autorefresh; }
        }

        /// <summary>
        /// If automatic DataSource Update ist on, this Property set the interval in seconds todo this
        /// </summary>
        public int RefreshIntervall
        {
            get { return m_RefreshIntervall; }
        }

        /// <summary>
        /// Contains the DataSource from all DataSourceItems
        /// </summary>
        public cStartmenuItem Data_DataSources
        {
            get { return m_Data; }
        }

        public Dictionary<string, Model.MenuConfig.DataSource> DatasourceItems
        {
            get { return m_Items; }
            set { m_Items = value; }
        }
        #endregion

        #region Public Methods

        public bool IsDataSourceUpdated(string DataSource)
        {
            try
            {
                if (m_Items[DataSource].LastUpdate < m_Items[DataSource].InstanceDataSourceItem.LastUpdated)
                {
                    m_Items[DataSource].LastUpdate = m_Items[DataSource].InstanceDataSourceItem.LastUpdated;
                    return true;
                }
                else return false;
            }
            catch (Exception Ex)
            {
                throw new Exception("Can't Test Update for DataSource '" + DataSource + "'", Ex);
            }
        }

        public iWinKStartDataSource GetDataSourceInstance(string DataSource)
        {
            try
            {
                if (m_Data.ChildItems.ContainsKey(DataSource) == true)
                {
                    return ((Model.MenuConfig.DataSource)m_Data.ChildItems[DataSource]).InstanceDataSourceItem;
                }
                else return null;
            }
            catch (Exception Ex)
            {
                throw new Exception("Can't get instance for DataSource '" + DataSource + "'", Ex);
            }
        }

        /// <summary>
        /// Get Data from DataSources
        /// </summary>
        /// <param name="DataSource">Datasource from Data returns</param>
        /// <param name="Filter">Filter to select a subfolderitem from DataSource</param>
        /// <returns>requested dataitems</returns>
        public cStartmenuItem GetData(string DataSource, string Filter)
        {
            try
            {
                if (m_Data.ChildItems.ContainsKey(StartMenuItemPrefix.STARTMENUITEM_PREFIX__DATASOURCEITEM_DATANAME +  DataSource.ToUpper()) == true)
                {
                    cStartmenuItem tmpResultItem = (cStartmenuItem)m_Data.ChildItems[StartMenuItemPrefix.STARTMENUITEM_PREFIX__DATASOURCEITEM_DATANAME + DataSource.ToUpper()];

                    string[] PathParts = Filter.Split(new char[] { '\\' });

                    if (PathParts != null && PathParts.Count() > 0)
                    {
                        for (int iPartCounter = 0; iPartCounter < PathParts.Count(); iPartCounter++){
                            if (tmpResultItem.ChildItems.ContainsKey(PathParts[iPartCounter].ToUpper()) == true)
                            {
                                tmpResultItem = (cStartmenuItem)tmpResultItem.ChildItems[PathParts[iPartCounter].ToUpper()];
                            }
                        }
                    }
                    
                    return tmpResultItem;
                    //m_Data.ChildItems[DataSource]
                }
                else throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_UNKNOWN_DATASOURCE);
            }
            catch (Exception Ex)
            {
                string sMessage = WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_CANT_GET_DATA;
                sMessage = sMessage.Replace("##DATASOURCE##",DataSource);
                throw new Exception(sMessage, Ex);
            }
        }

        public void Load(System.Xml.XmlNode Node, bool Initialize = true)
        {
            try
            {
                //Remove all existing items from list
                m_Items.Clear();

                if (Node != null)
                {
                    //first read all DataSources Attributes

                    if (Node.ChildNodes.Count > 0)
                    {
                        Model.MenuConfig.DataSource ChildItem = null;
                        cStartmenuItem tmpDataSourceData = null;
                        int iItemIndex = 0;
                        //Load ex child and create a DataSourceItem
                        foreach (System.Xml.XmlNode SubNode in Node.ChildNodes)
                        {
                            ChildItem = null;
                            tmpDataSourceData = null;

                            if (SubNode.Name == XMLNodeNames.DATASOURCE_XMLNODE__ADDDATASOURCE)
                            {
                                ChildItem = CreateDataSourceItem(SubNode);
                                tmpDataSourceData = new cStartmenuItem(StartMenuItemPrefix.STARTMENUITEM_PREFIX__DATASOURCEITEM_DATANAME + ChildItem.Name,
                                                                       "DataSource_" + ChildItem.Name, eLinkExecutionTypes.Program, "", 
                                                                       eExecutionProcedure.Unknown, eItemType.Root, "", null, m_Data, 
                                                                       "", "", "", "");
                                if (ChildItem != null)
                                {
                                    if (m_Data.ChildItems.ContainsKey(StartMenuItemPrefix.STARTMENUITEM_PREFIX__DATASOURCEITEM_DATANAME + 
                                        ChildItem.Name) == false)
                                    {
                                        m_Data.AddChild(tmpDataSourceData);
                                        if (m_Items.ContainsKey(ChildItem.Name) == false)
                                        {
                                            m_Items.Add(ChildItem.Name, ChildItem);
                                            iItemIndex++;
                                        }
                                    }
                                }
                            }
                        }
                        if (Initialize) InitDataSourceItems();
                        //TODO: now we update the data
                        //UpdateData();
                    }
                }
                else
                {
                    throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_CANT_READ_DATASOURCE_CONFIG);
                }
            }
            catch (Exception Ex)
            {                
                throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_WHILE_LOADING_DATASOURCES, Ex);
            }
        }

        /// <summary>
        /// Stop all running thread from Datasources
        /// </summary>
        /// <returns></returns>
        public bool Unload()
        {
            try
            {
                Dictionary<string, Model.MenuConfig.DataSource>.KeyCollection tmpKeys = m_Items.Keys;
                foreach (string KeyItem in tmpKeys)
                {
                    if (m_Items[KeyItem].InstanceDataSourceItem != null)
                    {
                        m_Items[KeyItem].InstanceDataSourceItem.UnloadDataSource();
                    }
                }
                return true;
            }
            catch (Exception Ex)
            {

                return false;
            }
        }

        #endregion

        #region Private Methods

        private void DataSourceItem_LoadCompleted(object sender, EventArgs e)
        {
            try
            {
                if ( sender != null ) {
                    Interfaces.iWinKStartDataSource tmpClassInstance = ((Interfaces.iWinKStartDataSource)sender);
                    m_Data.ChildItems[((string)StartMenuItemPrefix.STARTMENUITEM_PREFIX__DATASOURCEITEM_DATANAME +
                                      tmpClassInstance.Name).ToUpper()] = tmpClassInstance.Data;

                    if (UpdatedDataSource != null) UpdatedDataSource(this, m_Items[tmpClassInstance.Name]);
                }
            }
            catch (Exception Ex)
            {
                CMessagelogging.AppendMessage(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_CANT_UPDATE_DATA_FROM_DATASOURCE, Ex, 
                                              EMessageTypes.Error);
            }
        }

        private void InitDataSourceItems()
        {
            try
            {
                CMessagelogging.AppendMessage("Initialise DateSource - Items!", EMessageTypes.Debug);

                Dictionary<string, Model.MenuConfig.DataSource>.KeyCollection tmpKeys = m_Items.Keys;
                foreach (string KeyItem in tmpKeys)
                {
                    if (m_Items.ContainsKey(KeyItem) == true)
                    {
                        iWinKStartDataSource tmpDSInstance = LoadDataSourceItem(m_Items[KeyItem].Name,
                                                                                m_Items[KeyItem].Assembly,
                                                                                m_Items[KeyItem].ClassName,
                                                                                m_Items[KeyItem].Items);
                        tmpDSInstance.Assignments = m_Items[KeyItem].ExtensionsDict;
                        tmpDSInstance.Options = m_Items[KeyItem].OptionsDict;
                        m_Items[KeyItem].InstanceDataSourceItem = tmpDSInstance;
                        //Initialise DataSource
                        tmpDSInstance.Init();
                    }
                    else
                        throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_WRONG_DATASOURCE_PRIORTITY);
                }
            }
            catch (Exception Ex)
            {               
                throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_CANT_INIT_DATASOURCEITEMS, Ex);
            }
        }

        /// <summary>
        /// Create a DataSourceItem - Instance from XML - Node
        /// </summary>
        /// <param name="Node">XML - Node to create instance</param>
        /// <returns></returns>
        private Model.MenuConfig.DataSource CreateDataSourceItem(System.Xml.XmlNode Node)
        {
            try
            {
                if (Node != null)
                {
                    Model.MenuConfig.DataSource tmpItem = new Model.MenuConfig.DataSource(
                                        Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__NAME].InnerText,
                                        Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__ASSEMBLY].InnerText,
                                        Node.Attributes[XMLNodeNames.DATASOURCE_XMLNODE_ATTRIBUTE__CLASSNAME].InnerText);
                    if (tmpItem != null)
                    {
                        //TODO: reading the new attzributes ShortName and searchable
                        tmpItem.ShortName = Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__SHORTNAME].InnerText;
                        tmpItem.Searchable = bool.Parse(Node.Attributes[XMLNodeNames.MENUCONFIG_XMLNODE_ATTRIBUTE__SEARCHENABLE].InnerText);
                    }
                    //TODO read all manual added Items
                    if (Node.ChildNodes.Count > 0)
                    {
                        foreach (System.Xml.XmlNode ChildNode in Node.ChildNodes)
                        {
                            if (ChildNode.Name == XMLNodeNames.MENUCONFIG_XMLNODE_SUBNODE__ITEMS)
                            {
                                //load manually added DataItems
                                if (ChildNode.ChildNodes.Count > 0)
                                {
                                    foreach (System.Xml.XmlNode SubChildNode in ChildNode.ChildNodes)
                                    {
                                        cStartmenuItem tmpStartItem = cMenuConfigReader.CreateMenuItemFromXML(SubChildNode);
                                        if (tmpStartItem != null)
                                        {
                                            tmpItem.Items.Add(tmpStartItem);
                                        }
                                    }
                                }
                            }
                            else if (ChildNode.Name == XMLNodeNames.MENUCONFIG_XMLNODE_SUBNODE__ASSIGNMENTS)
                            {
                                //Load added Assignments
                                if (ChildNode.ChildNodes.Count > 0)
                                {
                                    foreach (System.Xml.XmlNode SubChildNode in ChildNode.ChildNodes)
                                    {
                                        KeyValueAssignment Item = cMenuConfigReader.CreateKeyValueAssignmentFromXML(SubChildNode);
                                        //TODO add to dictionary
                                        if (tmpItem.ExtensionsDict.ContainsKey(Item.Key.ToUpper()) == false)
                                        {
                                            tmpItem.ExtensionsDict.Add(Item.Key.ToUpper(), Item);
                                        }
                                    }
                                }
                            }
                            else if (ChildNode.Name == XMLNodeNames.MENUCONFIG_XMLNODE_SUBNODE__OPTIONS)
                            {
                                //Load added Options
                                if (ChildNode.ChildNodes.Count > 0)
                                {
                                    foreach (System.Xml.XmlNode SubChildNode in ChildNode.ChildNodes)
                                    {
                                        KeyValueAssignment Item = cMenuConfigReader.CreateKeyValueAssignmentFromXML(SubChildNode);
                                        //TODO add to dictionary
                                        if (tmpItem.OptionsDict.ContainsKey(Item.Key.ToUpper()) == false)
                                        {
                                            tmpItem.OptionsDict.Add(Item.Key.ToUpper(), Item);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    return tmpItem;
                } return null;
            }
            catch (Exception Ex)
            {
                throw new Exception(WMSSoft.Lib.Texte.ErrorMessages.DATASOURCE_READER__ERROR_CANT_READ_DATASOURCEITEM, Ex);
            }
        }

        /// <summary>
        /// Create a instance from DataSourceItem given class
        /// </summary>
        /// <param name="AssembyFileName">Assembly Filename to load</param>
        /// <param name="FQCN">Full Qualified Class Name</param>
        /// <returns>Instance from DataSourceItem to get Data</returns>
        private iWinKStartDataSource LoadDataSourceItem(string Name, string AssembyFileName, string FQCN, List<iWinKStartItem> Items)
        {
            try
            {
                string tmpDataSourcesPath = System.IO.Path.Combine(cUserSettingsReader.DataSourcesPath, AssembyFileName);
                System.Reflection.Assembly tmpAssembly = System.Reflection.Assembly.LoadFile(tmpDataSourcesPath);
                iWinKStartDataSource tmpDSInstance = (iWinKStartDataSource)tmpAssembly.CreateInstance(FQCN);
                if (tmpDSInstance != null)
                {
                    tmpDSInstance.Name = Name;
                    tmpDSInstance.AssemblyName = AssembyFileName;
                    tmpDSInstance.ClassName = FQCN;
                    tmpDSInstance.Items = Items;
                    //Apply data if loading completed
                    tmpDSInstance.LoadCompleted += DataSourceItem_LoadCompleted;
                }

                return tmpDSInstance;
            }
            catch (Exception Ex) 
            {
                string sMessage = WMSSoft.Lib.Texte.ErrorMessages.FAVORITE_READER__ERROR_DATASOURCE_ASSEMBLY_LOAD_FAILED;
                sMessage = sMessage.Replace("##AssemblyName##", AssembyFileName);
                sMessage = sMessage.Replace("##FQCN##", FQCN);
                CMessagelogging.AppendMessage(sMessage, Ex, EMessageTypes.Error);
                return null;
            }
        }

        #endregion
    }
}
